package com.vdong.common.oauth.service.impl;


import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.sd4324530.fastweixin.api.ComponentOauthAPI;
import com.github.sd4324530.fastweixin.api.config.ComponentApiConfig;
import com.github.sd4324530.fastweixin.api.response.OauthGetTokenResponse;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.vdong.common.oauth.common.enums.*;
import com.vdong.common.oauth.common.exception.WebBizException;
import com.vdong.common.oauth.common.util.AbstractOpenPlatformSupport;
import com.vdong.common.oauth.entity.dto.PayConfigDTO;
import com.vdong.common.oauth.entity.dto.WechatAuthorizerInfoVO;
import com.vdong.common.oauth.entity.mo.FuncInfo;
import com.vdong.common.oauth.entity.mo.WechatAuthorizerInfo;
import com.vdong.common.oauth.entity.mo.WechatOpenPlatform;
import com.vdong.common.oauth.service.SmsVerificationCodeService;
import com.vdong.common.oauth.service.WechatAuthorizerInfoService;
import com.vdong.common.oauth.service.WechatService;
import com.vdong.common.oauth.repository.dao.WechatAuthorizerInfoMapper;
import com.vdong.common.oauth.repository.dao.WechatOpenPlatformMapper;
import com.vdong.interactive.file.facade.CCSClientFacade;
import com.vdong.trade.trading.facade.PayConfigFacade;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.lamb.framework.common.remote.FacadeResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
@Service
public class WechatAuthorizerInfoServiceImpl extends AbstractOpenPlatformSupport implements WechatAuthorizerInfoService {

    @Autowired
    private OauthDynamicPropertyService oauthDynamicPropertyService;

    //private String token = oauthDynamicPropertyService.getToken();

    //private String appid = oauthDynamicPropertyService.getAppid();

    //private String secret = oauthDynamicPropertyService.getSecret();

    //private String key = oauthDynamicPropertyService.getKey();

    //private String h5Url = oauthDynamicPropertyService.getH5Url();

    @Resource
    private WechatService wechatService;

    @Resource
    private RedisTemplate redisTemplate;


    @Autowired
    private WechatAuthorizerInfoMapper wechatAuthorizerInfoMapper;

    @Resource
    private WechatAuthorSerivce wechatAuthorSerivce;

    @Resource
    private WechatOpenPlatformMapper wechatOpenPlatformMapper;

    @Reference
    private CCSClientFacade ccsClientFacade;

    @Resource
    private WechatPlatformService wechatOpenPlatformService;

    @Resource
    private SmsVerificationCodeService smsVerificationCodeService;

    @Reference
    private PayConfigFacade payConfigFacade;


    @Override
    protected String getToken() {
        return oauthDynamicPropertyService.getToken();
    }

    @Override
    protected String getAppId() {
        return oauthDynamicPropertyService.getAppid();
    }

    @Override
    protected String getAESKey() {
        return oauthDynamicPropertyService.getKey();
    }

    @Override
    protected String getSecret() {
        return oauthDynamicPropertyService.getSecret();
    }

    @Override
    protected RedisTemplate getRedisTemplate() {
        StringRedisTemplate template = new StringRedisTemplate(redisTemplate.getConnectionFactory());
        JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer();
        template.setHashKeySerializer(jdkSerializationRedisSerializer);
        template.setValueSerializer(jdkSerializationRedisSerializer);
        return template;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveAuthInfo(Long storeId, String authCode, AuthorizeTypeEnum authorizeType) {
        WechatAuthorizerInfo wechatAuthorizerInfo = wechatAuthorSerivce.getAuthInfoFromWeixin(authCode);
        if (wechatAuthorizerInfo == null) {
            throw new WebBizException("获取微信授权信息失败");
        }
        log.debug("saveAuthInfo >>>>>>>> storeId:{} , authCode:{} ,authorizeType:{} ,wechatAuthorizerInfo:{}",
                storeId, authCode, authorizeType.getDesc(), wechatAuthorizerInfo.toString());
        validateWechatAuthorizerInfo(wechatAuthorizerInfo, authorizeType);
        wechatAuthorizerInfo.setStoreId(storeId);
        wechatAuthorizerInfo.setStatus(1);

        WechatAuthorizerInfo info = loadByStoreId(storeId, authorizeType);
        if (info == null) {

            if (wechatAuthorizerInfoMapper.selectByAppId(wechatAuthorizerInfo.getAppid(), authorizeType.getCode()).size() > 0) {
                throw new WebBizException("该" + authorizeType.getDesc() + "已经被其他店铺绑定，无法授权");
            }
            String qiniuDomain = "kpay.qiniu.vdlb.cn";
            String toKey = String.format("resource/image/jpeg/h5_app_qr_code/appId_%s.jpg", wechatAuthorizerInfo.getAppid());
            String url = ccsClientFacade.fetch(wechatAuthorizerInfo.getQrcodeUrl(), null, toKey);
            //"?wx_fmt=jpeg&wxfrom=5&wx_lazy=1"
//            String qrcodeUrlKey = qiniuKodo.fetch(info.getQrcodeUrl(), null, toKey);
            wechatAuthorizerInfo.setQrcodeUrl(url);
//            二维码生成
//            switch (authorizeType) {
//                case Mini:
//                    String qrcode = wechatQrcodeSerivce.genMiniAppQrcode(wechatAuthorizerInfo, "" + storeId, "", null);
//                    wechatAuthorizerInfo.setQrcodeUrl(qrcode);
//                    break;
//                case Open:
//                    String h5Qrcode = wechatQrcodeSerivce.genH5AppQrcode(wechatAuthorizerInfo);
//                    wechatAuthorizerInfo.setQrcodeUrl(h5Qrcode);
//                    break;
//            }
            //绑定开放平台
            wechatOpenPlatformService.bindOpenPlatform(wechatAuthorizerInfo);
            wechatAuthorizerInfo.setCreateTime(new Date());
            wechatAuthorizerInfoMapper.insert(wechatAuthorizerInfo);
        } else {
            if (!StringUtils.equals(wechatAuthorizerInfo.getAppid(), info.getAppid())) {
                throw new WebBizException("重新授权时必须是同一" + authorizeType.getDesc() + " ，授权失败");
            }
            wechatAuthorizerInfo.setQrcodeUrl(info.getQrcodeUrl());
            //绑定开放平台
            wechatOpenPlatformService.bindOpenPlatform(wechatAuthorizerInfo);
            wechatAuthorizerInfo.setCreateTime(new Date());
            wechatAuthorizerInfo.setModifyTime(new Date());
            wechatAuthorizerInfoMapper.updateByPrimaryKey(wechatAuthorizerInfo);
        }
        if (authorizeType.getCode() == AuthorizeTypeEnum.Mini.getCode()) {
            //修改域名
            wechatAuthorSerivce.modifyDomain(wechatAuthorizerInfo.getAppid(), wechatAuthorizerInfo.getRefreshToken());
        }
        return Boolean.TRUE;
    }

    private void validateWechatAuthorizerInfo(WechatAuthorizerInfo wechatAuthorizerInfo, AuthorizeTypeEnum authorizeType) {
        if (wechatAuthorizerInfo.getAuthorizeType() != authorizeType.getCode()) {
            throw new WebBizException("该授权账号类型与当前授权入口类型不一致，授权失败");
        }
        //账号权限校验
        if (StringUtils.isEmpty(wechatAuthorizerInfo.getFuncInfo())) {
            throw new WebBizException("权限不足，请保证您已将所有权限集授权给学兽");
        }
        //获取权限集id
        List<Integer> funcIds = new ArrayList<>();
        List<FuncInfo> rule = new Gson().fromJson(wechatAuthorizerInfo.getFuncInfo(), new TypeToken<List<FuncInfo>>() {
        }.getType());
        rule.forEach(rules -> {
            funcIds.add(rules.getFuncscopeCategory().get("id"));
        });
        Integer param = 2;
        switch (authorizeType) {
            case Open:
                if (!funcIds.contains(PowerTypeEnum.Public.getCode())) {
                    throw new WebBizException("权限不足，请保证您已将所有权限集授权给学兽");
                }
                if (param.equals(wechatAuthorizerInfo.getServiceTypeInfo())) {
                    throw new WebBizException("账号类型不匹配，请确认您的账号是已认证通过的服务号");
                }
                break;
            case Mini:
                if (!funcIds.contains(PowerTypeEnum.Program.getCode())) {
                    throw new WebBizException("权限不足，请保证您已将所有权限集授权给学兽");
                }

                break;
            default:
                throw new WebBizException("权限不足");
        }

        if (0 != wechatAuthorizerInfo.getVerifyTypeInfo()) {
            throw new WebBizException("账号类型不匹配，请确认您的账号是已认证通过的" + authorizeType.getDesc());
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveAuthInfo(String appId, String authCode) {
        log.debug("更新授权信息 appId:{} ,authCode:{} ", appId, authCode);
        return true;
       /* if (StringUtils.isEmpty(appId)) {
            return false;
        }
        WechatAuthorizerInfo info = wechatAuthorizerInfoMapper.selectByPrimaryKey(appId);
        if (info == null) {
            return false;
        }
        WechatAuthorizerInfo wechatAuthorizerInfo = wechatAuthorSerivce.getAuthInfoFromWeixin(authCode);
        if (wechatAuthorizerInfo == null) {
            return false;
        }
        validateWechatAuthorizerInfo(wechatAuthorizerInfo);
        wechatAuthorizerInfo.setAppid(appId);
        info.setStatus(1);
        return wechatAuthorizerInfoMapper.updateByPrimaryKeySelective(info) == (1);*/
    }


    private OauthGetTokenResponse getOpenId(String code, String appid, String secret) {
        // OauthAPI oauthAPI = new OauthAPI(super.getApiConfig(appid, secret));
        ComponentApiConfig apiConfig = super.getComponentApiConfig();
        ComponentOauthAPI api = new ComponentOauthAPI(apiConfig);
        OauthGetTokenResponse response = api.getToken(code, appid);
        if (api.isSuccess(response.getErrcode())) {
            throw new WebBizException("...获取授权信息失败:" + response.getErrmsg());
        }
        return response;
    }

    /**
     * 公众号或小程序取消授权
     */
    @Override
    public Boolean unauthorized(String appid) {
        WechatAuthorizerInfo info = wechatAuthorizerInfoMapper.selectByPrimaryKey(appid);
        if (info != null) {
            //清理缓存
            wechatAuthorSerivce.clearAuthorizerCache(appid);
            info = new WechatAuthorizerInfo();
            info.setAppid(appid);
            info.setStatus(0);
            return wechatAuthorizerInfoMapper.updateByPrimaryKey(info) == (1);
        }
        return false;
    }

    @Override
    public WechatAuthorizerInfo loadByAppid(String appid) {
        return wechatAuthorizerInfoMapper.selectByPrimaryKey(appid);
    }

    @Override
    public WechatAuthorizerInfo loadByStoreId(Long storeId) {
        return loadByStoreId(storeId, AuthorizeTypeEnum.Mini);
    }

    @Override
    public WechatAuthorizerInfo loadByStoreId(Long storeId, AuthorizeTypeEnum authorizeType) {

        List<WechatAuthorizerInfo> infos = wechatAuthorizerInfoMapper.selectByStoreId(storeId, authorizeType.getCode());
        return infos.size() > 0 ? infos.get(0) : null;
    }

    @Override
    public Boolean isAuth(Long storeId) {
        return isAuth(storeId, AuthorizeTypeEnum.Mini);
    }

    @Override
    public Boolean isAuth(Long storeId, AuthorizeTypeEnum authorizeType) {
        WechatAuthorizerInfo info = loadByStoreId(storeId, authorizeType);
        if (info == null) {
            return Boolean.FALSE;
        }
        return info.getStatus() != null && info.getStatus() == 1;
    }

    @Override
    public WechatAuthorizerInfoVO getAuthorizerInfo(Long storeId, AuthorizeTypeEnum authorizeType) {
        List<WechatAuthorizerInfo> list = wechatAuthorizerInfoMapper.selectByStoreId(storeId, authorizeType.getCode());
        if (null == list || list.size() == 0) {
            return WechatAuthorizerInfoVO.builder().build();
        }
        WechatAuthorizerInfo info = list.get(0);


        WechatOpenPlatform wechatOpenPlatform = null;
        if (StringUtils.isNotEmpty(info.getOpenId())) {
            wechatOpenPlatform = wechatOpenPlatformMapper.selectByOpenId(info.getOpenId());
        }

        List<Integer> funcIds = new ArrayList<>();
        List<FuncInfo> rule = new Gson().fromJson(info.getFuncInfo(), new TypeToken<List<FuncInfo>>() {
        }.getType());
        rule.forEach(rules -> {
            funcIds.add(rules.getFuncscopeCategory().get("id"));
        });
        WechatAuthorizerInfoVO vo = WechatAuthorizerInfoVO.builder()
                .appid(info.getAppid())
                .storeId(info.getStoreId())
                .nickName(info.getNickName())
                .headImg(info.getHeadImg())
                .serviceTypeInfo(info.getServiceTypeInfo())
                .verifyTypeInfo(info.getVerifyTypeInfo())
                .userName(info.getUserName())
                .signature(info.getSignature())
                .principalName(info.getPrincipalName())
                .alias(info.getAlias())
                .qrcodeUrl(info.getQrcodeUrl())
                .businessInfo(info.getBusinessInfo())
                .miniprograminfo(info.getMiniprograminfo())
                .funcIds(funcIds)
                .createTime(info.getCreateTime())
                .modifyTime(info.getModifyTime())
                .authorizeType(info.getAuthorizeType())
                .wechatOpenPlatform(wechatOpenPlatform)
                .status(info.getStatus()).build();
        switch (authorizeType) {
            case Mini:
                break;
            case Open:
                vo.setH5Url("http://" + oauthDynamicPropertyService.getH5Url());
                //vo.setQrcodeUrl(vo.getQrcodeUrl() + "?wx_fmt=jpeg&wxfrom=5&wx_lazy=1");
                break;
            default:
        }
        return vo;
    }

    @Override
    public Boolean unbundAuthorizerInfo(String appId, String phone, String code) {
        Boolean aBoolean = smsVerificationCodeService.checkIsCorrectCode(phone, SmsConstant.VerifyCodeType.DEL_AUTH,
                PlatformEnum.WEB, code);
        if (!aBoolean) {
            throw new WebBizException("请输入正确的验证码");
        }
        int falg = wechatAuthorizerInfoMapper.deleteByPrimaryKey(appId);
        wechatAuthorSerivce.clearAuthorizerCache(appId);
        return falg > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteAuth(String appId) {
        WechatOpenPlatform wechatOpenPlatform = wechatOpenPlatformService.getOpenPlatform(-1L);
        wechatOpenPlatformMapper.deleteByPrimaryKey(wechatOpenPlatform.getId());
        int falg = wechatAuthorizerInfoMapper.deleteByPrimaryKey(appId);
        wechatAuthorSerivce.clearAuthorizerCache(appId);
        return falg > 0;
    }

    @Override
    public Boolean savaOrUpdatePay(PayConfigDTO payConfigDTO) {
        PayConfigDTO result = selectPayConfig();
        WechatAuthorizerInfo wechatAuthorizerInfo = loadByStoreId(-1L, AuthorizeTypeEnum.Open);
        boolean flag = false;
        if (null == result.getId()) {
            try {
                payConfigDTO.setAppId(wechatAuthorizerInfo.getAppid());
                payConfigDTO.setAppName(wechatAuthorizerInfo.getNickName());
                FacadeResult<String> facadeResult = payConfigFacade.insert(JSON.toJSONString(payConfigDTO));
                flag = facadeResult.isSuccess();
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            try {
                payConfigDTO.setId(result.getId());
                FacadeResult<String> facadeResult = payConfigFacade.update(JSON.toJSONString(payConfigDTO));
                flag = facadeResult.isSuccess();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return flag;
    }

    @Override
    public PayConfigDTO selectPayConfig() {
        WechatAuthorizerInfo wechatAuthorizerInfo = loadByStoreId(-1L, AuthorizeTypeEnum.Open);
        PayConfigDTO payConfigDTO = null;
        try {
            Optional.ofNullable(wechatAuthorizerInfo).orElseThrow(() -> new Exception("未授权"));
            FacadeResult<String> facadeResult = payConfigFacade.selectPayConfigList(null);
            String data = facadeResult.getData();
            JSONArray array = JSONArray.parseArray(data);
            List<PayConfigDTO> list = array.stream().map(a ->
                    JSONObject.parseObject(JSON.toJSONString(a), PayConfigDTO.class)).filter(a -> a.getAppId().equals(wechatAuthorizerInfo.getAppid())).collect(Collectors.toList());
            Optional.ofNullable(list).orElseThrow(() -> new Exception("支付配置不存在"));
            if (0 == list.size()) {
                return PayConfigDTO.builder().build();
            }
            payConfigDTO = list.get(0);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return payConfigDTO;
    }

}
